package astar;

/**
 * Created by estate on 2017/2/24.
 */


import java.lang.Math;
import java.util.*;


/**
 * Created by estate on 2017/2/18.
 */

public class AstarVisit {

    private static Node[][] map;
    private PriorityQueue<Node> openList;// 11
    private List<Node> closeList;

    public static Node start;
    Node target;
    Node current;
    public List listPath;

    public static Comparator<Node> F_Comparator = new Comparator<Node>() {
        @Override
        public int compare(Node c1, Node c2) {
            return (int) (c1.getF() - c2.getF());
        }
    };


    public AstarVisit(int[][] map) {
        this.map = new Node[map.length][map.length];
        for (int x = 0; x < map.length; x++) {
            for (int y = 0; y < map[0].length; y++) {
                this.map[x][y] = new Node(x, y, map[x][y]);
            }
        }
        
        this.openList = new PriorityQueue<>(10, F_Comparator);
        closeList = new ArrayList<Node>();
        listPath = new ArrayList<Node>();
    }

    public List<Node> Init(int x1, int y1, int x2, int y2) {

        this.start = this.map[x1][y1];
        this.target = this.map[x2][y2];

        CountG(start, null, 0);
        CountH(start, target);
        CountF(start);

        target.setG(start.getH());
        target.setH(0);
        CountF(target);

        start.setStatus(11);
        
        //target.setStatus(11);

        List<Node> result = new ArrayList<Node>(openList);

        return result;
    }

    public void Visit() {

        start.setStatus(22);
        closeList.add(start);
        
        current = new Node(start.getX(), start.getY(), start.getBlock());
        current.setH(start.getH());
        
        listPath.add(start);


        while (current.getH()!=0){
        	
        	

            if (current.getY() + 1 <= map.length) {
            	
                if (map[current.getX()][current.getY()+1].getBlock() == 0&&!closeList.contains(map[current.getX()][current.getY()+1])) {
                	map[current.getX()][current.getY()+1].setParent(current);
                    CountH(map[current.getX()][current.getY()+1], target);
                    CountG(map[current.getX()][current.getY()+1], current, current.getG() + 1);
                    CountF(map[current.getX()][current.getY()+1]);
                    openList.add(map[current.getX()][current.getY()+1]);
                }else if(closeList.contains(map[current.getX()][current.getY()+1])){} 
                else{
                	closeList.add(map[current.getX()][current.getY()+1]);
                }
                
                if (map[current.getX()][current.getY()+1].getBlock() == 1&&current.getY()-1>=0) {
                    
                    map[current.getX()][current.getY()-1].setH(map[current.getX()][current.getY()-1].getH()+2);
                    current.setH(current.getH()+2);
                }
            }

            if (current.getX() + 1 <= map.length) {
            	
                if (map[current.getX()+1][current.getY()].getBlock() == 0&&!closeList.contains(map[current.getX()+1][current.getY()])) {
                	map[current.getX()+1][current.getY()].setParent(current);
                    CountH(map[current.getX()+1][current.getY()], target);
                    CountG(map[current.getX()+1][current.getY()], current, current.getG() + 1);
                    CountF(map[current.getX()+1][current.getY()]);
                    openList.add(map[current.getX()+1][current.getY()]);
                }else if(closeList.contains(map[current.getX()+1][current.getY()])){} 
                else {
                    closeList.add(map[current.getX()+1][current.getY()]);
                    
                }
                if (map[current.getX()+1][current.getY()].getBlock() == 1&&current.getX()-1>=0) {
                	map[current.getX()-1][current.getY()].setH(map[current.getX()-1][current.getY()].getH()+2);
                	current.setH(current.getH()+2);
                }
            }


            if (current.getY() - 1 >= 0) {
            	
                if (map[current.getX()][current.getY()-1].getBlock() == 0&&!closeList.contains(map[current.getX()][current.getY()-1])) {
                	map[current.getX()][current.getY()-1].setParent(current);
                    CountH(map[current.getX()][current.getY()-1], target);
                    CountG(map[current.getX()][current.getY()-1], current, current.getG() + 1);
                    CountF(map[current.getX()][current.getY()-1]);
                    openList.add(map[current.getX()][current.getY()-1]);
                }else if(closeList.contains(map[current.getX()][current.getY()-1])){} 
                else {
                    closeList.add(map[current.getX()][current.getY()-1]);
                    
                }
                if (map[current.getX()][current.getY()-1].getBlock() == 1&&current.getY()+1<map.length) {
                    map[current.getX()][current.getY()+1].setH(map[current.getX()][current.getY()+1].getH()+2);
                	current.setH(current.getH()+2);
                }
            }

            if (current.getX() - 1 >= 0) {
            	
                if (map[current.getX()-1][current.getY()].getBlock() == 0&&!closeList.contains(map[current.getX()-1][current.getY()])) {
                	map[current.getX()-1][current.getY()].setParent(current);
                    CountH(map[current.getX()-1][current.getY()], target);
                    CountG(map[current.getX()-1][current.getY()], current, current.getG() + 1);
                    CountF(map[current.getX()-1][current.getY()]);
                    openList.add(map[current.getX()-1][current.getY()]);
                }else if(closeList.contains(map[current.getX()-1][current.getY()])){} 
                else {
                    closeList.add(map[current.getX()-1][current.getY()]);
                    
                }
                if (map[current.getX()-1][current.getY()].getBlock() == 1&&current.getX()+1<map.length) {
                    map[current.getX()+1][current.getY()].setH(map[current.getX()+1][current.getY()].getH()+2);
                	current.setH(current.getH()+2);
                }
            }

            if (openList.size()==0){
            	current = current.getParent();
            }
            else{
            	current = this.openList.poll();
            }
            openList.clear();
            closeList.add(current);
            listPath.add(current);

        }





    }


    public List Path(){

        return listPath;

    }
//
//    public Node Compare(){
//
//
//     Node [] a=new Node[0];
//
//
//        for (int i = 0; i < optionList.size(); i++) {
//             for (int j = 0; j < optionList.size() - 1 - i; j++) {
//                 a[i] = (Node) optionList.get(i);
//                 a[j] = (Node) optionList.get(j);
//
//                 if (a[j].getF() > a[j + 1].getF()) {
//                     Node temp = a[j];
//                     a[j] = a[j + 1];
//                     a[j + 1] = temp;
//
//                 }
//
//             }
//         }
//
//     return a[0];
//    }












    private   void CountG(Node node, Node parent, int step) {
        if (parent == null) {
            node.setG(step);
        } else {
            node.setG(parent.getG() + step);
        }
    }

    private   void CountH(Node node, Node endNode) {
        node.setH((Math.abs(endNode.getX() - node.getX()) + Math.abs(endNode.getY() - node.getY())));
    }

    private   void CountF(Node node) {
        node.setF(node.getG() + node.getH());
    }

    private Node UpdateH(Node node,Node pre){
        pre.setH(Math.max(pre.getH(),node.getG() - pre.getG()));
        return pre;
    }


    private void UpdateList(Node node){
        List<Node> list = new ArrayList<Node>();
        while(!openList.isEmpty()){
            list.add(UpdateH(node, openList.poll()));
        }
        for (int i=0;i<list.size();i++){
            openList.add(list.get(i));
        }
    }


}